////
//
/// \file ./test/newline_parser_test.cpp
//
//  Copyright 2007 Chandler Carruth
//  
//  Licensed under the Apache License, Version 2.0 (the "License"); 
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//  
//    http://www.apache.org/licenses/LICENSE-2.0
//  
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
////

//  System Headers
#include  <stdlib.h>
#include  <string.h>
#include  <inttypes.h>

//  Library Headers
#include  <cppunit/TestFixture.h>
#include  <cppunit/extensions/HelperMacros.h>

//  Project Headers
#include  <inc/parser/newline_parser.hpp>


//  we define UTF-8 encodings here for convenience...

#define   LF_CSTR     "\x0A"
#define   CR_CSTR     "\x0D"
#define   CRLF_CSTR   "\x0D\x0A"
#define   NEL_CSTR    "\xC2\x85"
#define   FF_CSTR     "\x0C"
#define   LS_CSTR     "\xE2\x80\xA8"
#define   PS_CSTR     "\xE2\x80\xA9"

#define   MAKE_NEWLINE_CSTR_LITS( bname, aname, before, after )   \
  const char* bname ## _lf_ ## aname    = before LF_CSTR after; \
  const char* bname ## _cr_ ## aname    = before CR_CSTR after; \
  const char* bname ## _crlf_ ## aname  = before CRLF_CSTR after; \
  const char* bname ## _nel_ ## aname   = before NEL_CSTR after;  \
  const char* bname ## _ff_ ## aname    = before FF_CSTR after; \
  const char* bname ## _ls_ ## aname    = before LS_CSTR after; \
  const char* bname ## _ps_ ## aname    = before PS_CSTR after; 

//  some text patterns to match
const char*           nil   = "";

MAKE_NEWLINE_CSTR_LITS( nil, nil, "", "" );

MAKE_NEWLINE_CSTR_LITS( s, nil, " ", "" );
MAKE_NEWLINE_CSTR_LITS( t, nil, "\t", "" );
MAKE_NEWLINE_CSTR_LITS( ss, nil, "        ", "" );
MAKE_NEWLINE_CSTR_LITS( tt, nil, "\t\t\t\t\t\t\t\t", "" );

MAKE_NEWLINE_CSTR_LITS( nil, s, "", " " );
MAKE_NEWLINE_CSTR_LITS( nil, t, "", "\t" );
MAKE_NEWLINE_CSTR_LITS( nil, ss, "", "        " );
MAKE_NEWLINE_CSTR_LITS( nil, tt, "", "\t\t\t\t\t\t\t\t" );

MAKE_NEWLINE_CSTR_LITS( s, s, " ", " " );
MAKE_NEWLINE_CSTR_LITS( t, t, "\t", "\t" );
MAKE_NEWLINE_CSTR_LITS( ss, ss, "        ", "        " );
MAKE_NEWLINE_CSTR_LITS( tt, tt, "\t\t\t\t\t\t\t\t", "\t\t\t\t\t\t\t\t" );

MAKE_NEWLINE_CSTR_LITS( s, txt, " ", "foo" );
MAKE_NEWLINE_CSTR_LITS( t, txt, "\t", "foo" );
MAKE_NEWLINE_CSTR_LITS( ss, txt, "        ", "foo" );
MAKE_NEWLINE_CSTR_LITS( tt, txt, "\t\t\t\t\t\t\t\t", "foo" );

MAKE_NEWLINE_CSTR_LITS( s, s_txt, " ", " foo" );
MAKE_NEWLINE_CSTR_LITS( t, t_txt, "\t", "\tfoo" );
MAKE_NEWLINE_CSTR_LITS( ss, ss_txt, "        ", "        foo" );
MAKE_NEWLINE_CSTR_LITS( tt, tt_txt, "\t\t\t\t\t\t\t\t", "\t\t\t\t\t\t\t\tfoo" );

MAKE_NEWLINE_CSTR_LITS( txt, s, "foo", " " );
MAKE_NEWLINE_CSTR_LITS( txt, t, "foo", "\t" );
MAKE_NEWLINE_CSTR_LITS( txt, ss, "foo", "        " );
MAKE_NEWLINE_CSTR_LITS( txt, tt, "foo", "\t\t\t\t\t\t\t\t" );

MAKE_NEWLINE_CSTR_LITS( txt_s, s, "foo ", " " );
MAKE_NEWLINE_CSTR_LITS( txt_t, t, "foo\t", "\t" );
MAKE_NEWLINE_CSTR_LITS( txt_ss, ss, "foo        ", "        " );
MAKE_NEWLINE_CSTR_LITS( txt_tt, tt, "foo\t\t\t\t\t\t\t\t", "\t\t\t\t\t\t\t\t" );

MAKE_NEWLINE_CSTR_LITS( txt_s, s_txt, "foo ", " foo" );
MAKE_NEWLINE_CSTR_LITS( txt_t, t_txt, "foo\t", "\tfoo" );
MAKE_NEWLINE_CSTR_LITS( txt_ss, ss_txt, "foo        ", "        foo" );
MAKE_NEWLINE_CSTR_LITS( txt_tt, tt_txt, "foo\t\t\t\t\t\t\t\t", "\t\t\t\t\t\t\t\tfoo" );


class   newlineParserTest : public CppUnit::TestFixture, private newlineParser
{
  CPPUNIT_TEST_SUITE( newlineParserTest );

  CPPUNIT_TEST( test_create_nil );
  CPPUNIT_TEST( test_create_nil_lf_nil );
  
  CPPUNIT_TEST( test_create_s_lf_nil );
  CPPUNIT_TEST( test_create_t_lf_nil );
  CPPUNIT_TEST( test_create_ss_lf_nil );
  CPPUNIT_TEST( test_create_tt_lf_nil );

  CPPUNIT_TEST( test_create_nil_lf_s );
  CPPUNIT_TEST( test_create_nil_lf_t );
  CPPUNIT_TEST( test_create_nil_lf_ss );
  CPPUNIT_TEST( test_create_nil_lf_tt );

  CPPUNIT_TEST( test_create_s_lf_s );
  CPPUNIT_TEST( test_create_t_lf_t );
  CPPUNIT_TEST( test_create_ss_lf_ss );
  CPPUNIT_TEST( test_create_tt_lf_tt );

  CPPUNIT_TEST( test_create_s_lf_txt );
  CPPUNIT_TEST( test_create_t_lf_txt );
  CPPUNIT_TEST( test_create_ss_lf_txt );
  CPPUNIT_TEST( test_create_tt_lf_txt );

  CPPUNIT_TEST( test_create_s_lf_s_txt );
  CPPUNIT_TEST( test_create_t_lf_t_txt );
  CPPUNIT_TEST( test_create_ss_lf_ss_txt );
  CPPUNIT_TEST( test_create_tt_lf_tt_txt );

  CPPUNIT_TEST( test_create_txt_lf_s );
  CPPUNIT_TEST( test_create_txt_lf_t );
  CPPUNIT_TEST( test_create_txt_lf_ss );
  CPPUNIT_TEST( test_create_txt_lf_tt );

  CPPUNIT_TEST( test_create_txt_s_lf_s );
  CPPUNIT_TEST( test_create_txt_t_lf_t );
  CPPUNIT_TEST( test_create_txt_ss_lf_ss );
  CPPUNIT_TEST( test_create_txt_tt_lf_tt );

  CPPUNIT_TEST( test_create_txt_s_lf_s_txt );
  CPPUNIT_TEST( test_create_txt_t_lf_t_txt );
  CPPUNIT_TEST( test_create_txt_ss_lf_ss_txt );
  CPPUNIT_TEST( test_create_txt_tt_lf_tt_txt );
  
  CPPUNIT_TEST_SUITE_END();

private:
  
public:
  void
  test_create_nil( void )
  {
    unsigned int    i;

    CPPUNIT_ASSERT( !this->parse_newline( nil, 0, 0, i ) );
  };

  //
  //  Now we define a bunch of preprocessor macros to complement the
  //  ones above. This allows us to quickly build tests that assert on
  //  all the various newlines.
  //

#define   ASSERT_CREATE_NEWLINE( b_name, a_name, start, end, lf ) \
  unsigned int      i_ ## lf; \
  CPPUNIT_ASSERT( this->parse_newline( b_name ## _ ## lf ## _ ## a_name, \
    strlen( b_name ## _ ## lf ## _## a_name ), \
    start, i_ ## lf ) ); \
  CPPUNIT_ASSERT_EQUAL( \
    (unsigned int)( strlen( b_name ## _ ## lf ## _ ## a_name ) + end ), \
    i_ ## lf )

#define   TEST_CREATE_NEWLINES( b_name, a_name, start, end ) \
  void \
  test_create_ ## b_name ## _lf_ ## a_name( void ) \
  { \
    ASSERT_CREATE_NEWLINE( b_name, a_name, start, end, lf ); \
    ASSERT_CREATE_NEWLINE( b_name, a_name, start, end, cr ); \
    ASSERT_CREATE_NEWLINE( b_name, a_name, start, end, crlf ); \
    ASSERT_CREATE_NEWLINE( b_name, a_name, start, end, nel ); \
    ASSERT_CREATE_NEWLINE( b_name, a_name, start, end, ff ); \
    ASSERT_CREATE_NEWLINE( b_name, a_name, start, end, ls ); \
    ASSERT_CREATE_NEWLINE( b_name, a_name, start, end, ps ); \
  }
  
  TEST_CREATE_NEWLINES( nil, nil, 0, 0 );
  
  TEST_CREATE_NEWLINES( s, nil, 0, 0 );
  TEST_CREATE_NEWLINES( t, nil, 0, 0 );
  TEST_CREATE_NEWLINES( ss, nil, 0, 0 );
  TEST_CREATE_NEWLINES( tt, nil, 0, 0 );

  TEST_CREATE_NEWLINES( nil, s, 0, 0 );
  TEST_CREATE_NEWLINES( nil, t, 0, 0 );
  TEST_CREATE_NEWLINES( nil, ss, 0, 0 );
  TEST_CREATE_NEWLINES( nil, tt, 0, 0 );

  TEST_CREATE_NEWLINES( s, s, 0, 0 );
  TEST_CREATE_NEWLINES( t, t, 0, 0 );
  TEST_CREATE_NEWLINES( ss, ss, 0, 0 );
  TEST_CREATE_NEWLINES( tt, tt, 0, 0 );

  TEST_CREATE_NEWLINES( s, txt, 0, -3 );
  TEST_CREATE_NEWLINES( t, txt, 0, -3 );
  TEST_CREATE_NEWLINES( ss, txt, 0, -3 );
  TEST_CREATE_NEWLINES( tt, txt, 0, -3 );

  TEST_CREATE_NEWLINES( s, s_txt, 0, -3 );
  TEST_CREATE_NEWLINES( t, t_txt, 0, -3 );
  TEST_CREATE_NEWLINES( ss, ss_txt, 0, -3 );
  TEST_CREATE_NEWLINES( tt, tt_txt, 0, -3 );

  TEST_CREATE_NEWLINES( txt, s, 3, 0 );
  TEST_CREATE_NEWLINES( txt, t, 3, 0 );
  TEST_CREATE_NEWLINES( txt, ss, 3, 0 );
  TEST_CREATE_NEWLINES( txt, tt, 3, 0 );

  TEST_CREATE_NEWLINES( txt_s, s, 3, 0 );
  TEST_CREATE_NEWLINES( txt_t, t, 3, 0 );
  TEST_CREATE_NEWLINES( txt_ss, ss, 3, 0 );
  TEST_CREATE_NEWLINES( txt_tt, tt, 3, 0 );

  TEST_CREATE_NEWLINES( txt_s, s_txt, 3, -3 );
  TEST_CREATE_NEWLINES( txt_t, t_txt, 3, -3 );
  TEST_CREATE_NEWLINES( txt_ss, ss_txt, 3, -3 );
  TEST_CREATE_NEWLINES( txt_tt, tt_txt, 3, -3 );

/*
  void
  test_create_txt_ss( void )
  {
    unsigned int    i;

    CPPUNIT_ASSERT( !node->create( txt_ss, strlen( txt_ss ), 0, i ) );
    CPPUNIT_ASSERT( !node->create( txt_ss, strlen( txt_ss ), 1, i ) );
    CPPUNIT_ASSERT( !node->create( txt_ss, strlen( txt_ss ), 2, i ) );
    CPPUNIT_ASSERT( node->create( txt_ss, strlen( txt_ss ), 3, i ) );
    CPPUNIT_ASSERT_EQUAL( (unsigned int)( strlen( txt_ss ) ), i );
  };

  void
  test_create_txt_tt( void )
  {
    unsigned int    i;

    CPPUNIT_ASSERT( !node->create( txt_tt, strlen( txt_tt ), 0, i ) );
    CPPUNIT_ASSERT( !node->create( txt_tt, strlen( txt_tt ), 1, i ) );
    CPPUNIT_ASSERT( !node->create( txt_tt, strlen( txt_tt ), 2, i ) );
    CPPUNIT_ASSERT( node->create( txt_tt, strlen( txt_tt ), 3, i ) );
    CPPUNIT_ASSERT_EQUAL( (unsigned int)( strlen( txt_tt ) ), i );
  };
*/
};

CPPUNIT_TEST_SUITE_REGISTRATION( newlineParserTest );


